package com.day16;

/**
 * 例子，创建三个窗口卖票，总票数是100张，使用实现Runnable接口的方式
 * <p>
 * 多个线程之间存在共享数据，才会存在线程安全问题。
 * 存在线程的安全问题，待解决
 * <p>
 * 1.问题:卖票过程中，出现了重票和错票的问题，重票和错票————>线程安全问题
 * 2.问题出现的原因:当某个线程操作车票的过程中，尚未操作完成时，其他线程参与进来，也操作车票
 * 3.如何解决:当一个线程a在操作ticker的时候，其他线程不能参与进来，直到线程a操作完成ticket时，其他线程才可以开始操作ticket.
 * 这种情况即使线程a出现了阻塞，也不能被改变。
 * 4.在java当中，我们通过同步机制，来解决线程安全问题.
 * <p>
 * 方式一: 同步代码块
 * synchronized(同步监视器){
 * //需要被同步的代码
 * }
 * <p>
 * 说明:操作共享数据的代码，即为需要被同步的代码 -->不能包含代码多了，不能代码少了
 * 共享数据:多个线程共同操作的变量,比如:ticket就是共享数据
 * 同步监视器:俗称:锁。任何一个类的对象，都可以充当锁。
 * 要求:多个线程必须共用同一把锁。
 * <p>
 * 补充:在实现Runnable接口创建线程的方式中，可以考虑使用this来充当监视器
 * <p>
 * <p>
 * <p>
 * 方式二: 同步方法
 * 1.同步方法依然涉及到同步监视器，只是不需要我们显式的声明。
 * 2.非静态的同步方法，同步监视器是this
 *  静态同步方法，同步监视器是:当前类本身
 *
 * 5.同步的方式,解决了线程的安全问题。----好处
 * 操作同步代码时，只能有一个线程参与，其他的线程等待，相当于是一个单线程的过程，效率低。---局限性
 *
 *
 * 面试题:sleep() 和 wait()方法的异同?
 * 1.相同点: 一旦执行方法，都可以使得当前的线程进入阻塞状态
 *
 * 2.不同点:1.两个方法定义的位置不同: Thread类中声明sleep(),Object类中声明wait()方法
 *          2.调用范围不同:sleep()可以在任何需要的场景下调用，wait()必须在同步代码块或同步方法中使用
 *          3.如果两个方法都使用在同步代码块和同步代码中，sleep()不会释放锁。wait()会释放锁给其他线程。
 *
 *
 */
public class WindowsTest {
    public static void main(String[] args) {
        Widows1 widows1 = new Widows1();
        Thread thread1 = new Thread(widows1);
        Thread thread2 = new Thread(widows1);
        Thread thread3 = new Thread(widows1);

        thread1.setName("窗口1");
        thread2.setName("窗口2");
        thread3.setName("窗口3");

        thread1.start();
        thread2.start();
        thread3.start();


    }
}


class Widows1 implements Runnable {

    //共享数据
    private int ticker = 100;

    Object object = new Object();

    @Override
    public void run() {
        while (true) {
            //可以使用this来替代
            synchronized (this) {
                if (ticker > 0) {
                    try {
                        Thread.sleep(100);
                    } catch (InterruptedException e) {
                        e.printStackTrace();
                    }
                    System.out.println(Thread.currentThread().getName() + ":卖票,票号为" + ticker);
                    ticker--;
                } else {
                    break;
                }
            }
        }
    }
}


class Widows2 implements Runnable {

    //共享数据
    private int ticker = 100;

    Object object = new Object();

    @Override
    public void run() {
        while (true) {

            show();
        }
    }


    public synchronized void show() {
        //可以使用this来替代

        if (ticker > 0) {
            try {
                Thread.sleep(100);
            } catch (InterruptedException e) {
                e.printStackTrace();
            }
            System.out.println(Thread.currentThread().getName() + ":卖票,票号为" + ticker);
            ticker--;
        }
    }
}